package com.kongzue.stacklabelview;

import com.kongzue.stacklabelview.interfaces.OnLabelClickListener;
import com.kongzue.stacklabelview.utils.AttrUtils;
import ohos.agp.components.*;
import ohos.agp.components.element.ElementScatter;
import ohos.agp.utils.Color;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.util.ArrayList;
import java.util.List;

/**
 * Author: @Kongzue
 * Github: https://github.com/kongzue/
 * Homepage: http://kongzue.com/
 * Mail: myzcxhh@live.cn
 *
 * @since 2018/10/24 20:58
 */
public class StackLabel extends ComponentContainer implements Component.EstimateSizeListener, ComponentContainer.ArrangeListener {

    private static HiLogLabel hiLogLabel = new HiLogLabel(HiLog.LOG_APP, 0x222, "my_app");
    private int textColor = 0;
    private int textSize = 0;
    private int paddingVertical = 0;
    private int paddingHorizontal = 0;
    private int itemMargin = 0;
    private int itemMarginVertical = 0;
    private int itemMarginHorizontal = 0;
    private int maxLines = 0;
    private boolean deleteButton = false;

    private int deleteButtonImage = -1;
    private int labelBackground = -1;

    private boolean selectMode = false;
    private int selectBackground = -1;
    private int selectTextColor = -1;
    private int maxSelectNum = 0;
    private int minSelectNum = 0;

    private OnLabelClickListener onLabelClickListener;
    private Context context;
    private List<String> labels;
    private int widthSize;
    private String loadLabelsArray;

    /**
     * 初始化
     *
     * @param context context
     */
    public StackLabel(Context context) {
        super(context);
        this.context = context;
    }

    /**
     * 初始化
     *
     * @param context context
     * @param attrs attrs
     */
    public StackLabel(Context context, AttrSet attrs) {
        super(context, attrs);
        this.context = context;
        loadAttrs(context, attrs);
    }

    /**
     * 初始化
     *
     * @param context context
     * @param attrs attrs
     * @param defStyleAttr defStyleAttr
     */
    public StackLabel(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs);
        this.context = context;
        loadAttrs(context, attrs);
    }

    private void loadAttrs(Context context, AttrSet attrs) {
        try {
            // 默认值
            textColor = Color.argb(230, 0, 0, 0);
            textSize = dp2px(12);
            paddingVertical = dp2px(8);
            paddingHorizontal = dp2px(12);
            itemMargin = dp2px(4);
            deleteButton = false;

            textColor = AttrUtils.getColorValueByAttr(attrs, "textColor", new Color(textColor)).getValue();
            textSize = AttrUtils.getDimensionValueByAttr(attrs, "textSize", textSize);
            paddingVertical = AttrUtils.getDimensionValueByAttr(attrs, "paddingVertical", paddingVertical);
            paddingHorizontal = AttrUtils.getDimensionValueByAttr(attrs, "paddingHorizontal", paddingHorizontal);
            itemMargin = AttrUtils.getDimensionValueByAttr(attrs, "itemMargin", itemMargin);
            itemMarginVertical = AttrUtils.getDimensionValueByAttr(attrs, "itemMarginVertical", itemMarginVertical);
            itemMarginHorizontal = AttrUtils.getDimensionValueByAttr(attrs, "itemMarginHorizontal", itemMarginHorizontal);
            deleteButton = AttrUtils.getBooleanValueByAttr(attrs, "deleteButton", deleteButton);
            deleteButtonImage = AttrUtils.getIntValueByAttr(attrs, "deleteButtonImage", deleteButtonImage);
            labelBackground = AttrUtils.getIntValueByAttr(attrs, "labelBackground", labelBackground);
            selectMode = AttrUtils.getBooleanValueByAttr(attrs, "selectMode", selectMode);
            selectBackground = AttrUtils.getIntValueByAttr(attrs, "selectBackground", selectBackground);
            selectTextColor = AttrUtils.getColorValueByAttr(attrs, "selectTextColor", new Color(selectTextColor)).getValue();
            maxSelectNum = AttrUtils.getIntValueByAttr(attrs, "maxSelectNum", maxSelectNum);
            minSelectNum = AttrUtils.getIntValueByAttr(attrs, "minSelectNum", minSelectNum);
            maxLines = AttrUtils.getIntValueByAttr(attrs, "maxLines", minSelectNum);
            // 加载值
            if (minSelectNum > maxSelectNum && maxSelectNum != 0) {
                minSelectNum = 0;
            }

            loadLabelsArray = AttrUtils.getStringValueByAttr(attrs, "loadLabelsArray", loadLabelsArray);

            if (selectBackground == -1) {
                selectBackground = ResourceTable.Graphic_rect_label_bkg_select_normal;
            }
            if (labelBackground == -1) {
                labelBackground = ResourceTable.Graphic_rect_normal_label_button;
            }
        } catch (Exception e) {
            HiLog.info(hiLogLabel, "error-->" + e.getMessage());
        }
        setEstimateSizeListener(this);
        setArrangeListener(this);
    }

    private int dp2px(float dpValue) {
        return (int) (0.5f + dpValue * DisplayManager.getInstance().getDefaultDisplay(context).get().getAttributes().densityPixels);
    }

    private float px2dp(int pxValue) {
        return (pxValue / DisplayManager.getInstance().getDefaultDisplay(context).get().getAttributes().densityPixels);
    }

    private List<Component> items;
    private int newHeight = 0;

    @Override
    public boolean onArrange(int i, int i1, int i2, int i3) {
        return false;
    }

    @Override
    public boolean onEstimateSize(int width, int i1) {
        widthSize = EstimateSpec.getSize(width);
        setEstimatedSize(widthSize, newHeight); // 设置宽高
        refreshViews();
        return false;
    }

    private void refreshViews() {
        int maxWidth = getEstimatedWidth();

        if (labels != null && !labels.isEmpty()) {
            newHeight = 0;
            if (items != null && !items.isEmpty()) {
                int l1 = 0, t1 = 0, r1 = 0, b1 = 0, lines = 0;

                for (int i = 0; i < items.size(); i++) {
                    Component item = items.get(i);

                    int mWidth = Component.EstimateSpec.getSizeWithMode(maxWidth, EstimateSpec.UNCONSTRAINT); // AT_MOST：先按照最大宽度计算，如果小于则按实际值，如果大于，按最大宽度
                    int mHeight = Component.EstimateSpec.getSizeWithMode(0, EstimateSpec.UNCONSTRAINT); // UNSPECIFIED：不确定，根据实际情况计算
                    item.estimateSize(mWidth, mHeight);

                    int childWidth = item.getEstimatedWidth();
                    int childHeight = item.getEstimatedHeight();

                    if (childWidth > maxWidth) {
                        childWidth = maxWidth;
                    }
                    if ((l1 + childWidth) > maxWidth) {
                        l1 = 0;
                        t1 = t1 + childHeight;
                        lines++;
                    }

                    if (maxLines > 0 && lines >= maxLines) {
                        item.setVisibility(HIDE);
                        invalidate();
                    } else {
                        r1 = l1 + childWidth;

                        if (childWidth > maxWidth) {
                            r1 = maxWidth;
                        }

                        b1 = t1 + childHeight;

                        item.arrange(l1, t1, r1, b1);

                        l1 = l1 + childWidth;

                        newHeight = t1 + childHeight;
                    }
                }
            }
        }
    }

    public List<String> getLabels() {
        return labels;
    }

    public StackLabel setLabels(List<String> l) {
        labels = l;

        reloadViews();
        return this;
    }

    public boolean remove(int index) {
        if (labels == null) {
            return false;
        }
        labels.remove(index);
        reloadViews();
        return true;
    }

    public boolean remove(String label) {
        if (labels == null) {
            return false;
        }
        boolean flag = labels.remove(label);
        reloadViews();
        return flag;
    }

    public StackLabel setLabels(String[] arrays) {
        labels = new ArrayList<>();
        for (String s1 : arrays) {
            labels.add(s1);
        }

        reloadViews();
        return this;
    }

    public boolean isHave(String label) {
        if (labels == null) {
            return false;
        }
        return labels.contains(label);
    }

    public int count() {
        if (labels == null) {
            return 0;
        } else {
            return labels.size();
        }
    }

    public void reloadViews() {
        removeAllComponents();
        items = new ArrayList<>();
        if (labels != null && !labels.isEmpty()) {
            for (int i = 0; i < labels.size(); i++) {
                Component item = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_layout_label, null, false);
                addComponent(item);
                items.add(item);
            }
            initItem();
        }
    }

    public StackLabel addLabel(String label) {
        if (labels == null) {
            labels = new ArrayList<>();
        }
        labels.add(label);

        reloadViews();
        return this;
    }

    private List<Integer> selectIndexs = new ArrayList<>();

    private void initItem() {
        if (labels.size() != 0) {
            selectIndexs = new ArrayList<>();
            for (int i = 0; i < items.size(); i++) {
                Component item = items.get(i);
                String s = labels.get(i);
                DirectionalLayout boxLabel = (DirectionalLayout) item.findComponentById(ResourceTable.Id_box_label);
                Text txtLabel = (Text) item.findComponentById(ResourceTable.Id_txt_label);
                Image imgDelete = (Image) item.findComponentById(ResourceTable.Id_img_delete);
                txtLabel.setText(s);
                txtLabel.setTextColor(new Color(textColor));
                txtLabel.setTextSize(textSize);
                boxLabel.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical);
                ComponentContainer.LayoutConfig p = (ComponentContainer.LayoutConfig) boxLabel.getLayoutConfig();
                if (itemMarginHorizontal == 0 && itemMarginVertical == 0) {
                    p.setMargins(itemMargin, itemMargin, itemMargin, itemMargin);
                } else {
                    p.setMargins(itemMarginHorizontal, itemMarginVertical, itemMarginHorizontal, itemMarginVertical);
                }
                boxLabel.postLayout();
                if (deleteButton) {
                    imgDelete.setVisibility(VISIBLE);
                } else {
                    imgDelete.setVisibility(HIDE);
                }
                if (deleteButtonImage == -1) {
                    imgDelete.setPixelMap(deleteButtonImage);
                }
                boxLabel.setBackground(new ElementScatter(context).parse(labelBackground));
                setListener(boxLabel, i);

                if (whichIsSelected != null) {
                    for (String selectStr : whichIsSelected) {
                        if (s.equals(selectStr)) {
                            selectIndexs.add(i);
                            boxLabel.setBackground(new ElementScatter(context).parse(selectBackground));
                            txtLabel.setTextColor(new Color(selectTextColor));
                        }
                    }
                }
            }
            whichIsSelected = null;
        }
    }

    private void setListener(Component boxLabel, int index) {
        boxLabel.setClickedListener(component -> {
            if (selectMode) {
                for (Component item1 : items) {
                    DirectionalLayout boxLabel1 = (DirectionalLayout) item1.findComponentById(ResourceTable.Id_box_label);
                    Text txtLabel1 = (Text) item1.findComponentById(ResourceTable.Id_txt_label);
                    boxLabel1.setBackground(new ElementScatter(context).parse(labelBackground));
                    txtLabel1.setTextColor(new Color(textColor));
                    txtLabel1.setTextSize(textSize);
                }
                if (selectIndexs.contains(index)) {
                    if (selectIndexs.size() > minSelectNum) {
                        int ind = 0;
                        for (int i1 = 0; i1 < selectIndexs.size(); i1++) {
                            if (selectIndexs.get(i1) == index) {
                                ind = i1;
                                break;
                            }
                        }
                        selectIndexs.remove(ind);
                    }
                } else {
                    if (maxSelectNum == 1) {
                        selectIndexs.clear();
                    }
                    if (maxSelectNum <= 0 || selectIndexs.size() < maxSelectNum) {
                        selectIndexs.add(index);
                    }
                }
                for (int index1 : selectIndexs) {
                    Component item1 = items.get(index1);
                    DirectionalLayout boxLabel1 = (DirectionalLayout) item1.findComponentById(ResourceTable.Id_box_label);
                    Text txtLabel1 = (Text) item1.findComponentById(ResourceTable.Id_txt_label);
                    boxLabel1.setBackground(new ElementScatter(context).parse(selectBackground));
                    txtLabel1.setTextColor(new Color(selectTextColor));
                }
            }
            if (onLabelClickListener != null) {
                onLabelClickListener.onClick(index, component, labels.get(index));
            }
        });
    }

    public OnLabelClickListener getOnLabelClickListener() {
        return onLabelClickListener;
    }

    public StackLabel setOnLabelClickListener(OnLabelClickListener onLabelClickListener) {
        this.onLabelClickListener = onLabelClickListener;
        return this;
    }

    public boolean isDeleteButton() {
        return deleteButton;
    }

    public StackLabel setDeleteButton(boolean deleteButton) {
        this.deleteButton = deleteButton;
        initItem();
        return this;
    }

    public boolean isSelectMode() {
        return selectMode;
    }

    public StackLabel setSelectMode(boolean selectMode) {
        this.selectMode = selectMode;
        setLabels(labels);
        return this;
    }

    private List<String> whichIsSelected; // 初始化已选择列表

    public StackLabel setSelectMode(boolean selectMode, List<String> whichIsSelected) {
        this.selectMode = selectMode;
        if (selectMode) {
            this.whichIsSelected = whichIsSelected;
        } else {
            whichIsSelected = null;
        }
        setLabels(labels);
        return this;
    }

    public int getSelectBackground() {
        return selectBackground;
    }

    public StackLabel setSelectBackground(int selectBackground) {
        this.selectBackground = selectBackground;
        setLabels(labels);
        return this;
    }

    public int getSelectTextColor() {
        return selectTextColor;
    }

    public StackLabel setSelectTextColor(int selectTextColor) {
        this.selectTextColor = selectTextColor;
        return this;
    }

    public int getMaxSelectNum() {
        return maxSelectNum;
    }

    public StackLabel setMaxSelectNum(int maxSelectNum) {
        this.maxSelectNum = maxSelectNum;
        setLabels(labels);
        return this;
    }

    public List<Integer> getSelectIndexList() {
        return selectIndexs;
    }

    public int[] getSelectIndexArray() {
        int[] arrays = new int[selectIndexs.size()];
        for (int i = 0; i < selectIndexs.size(); i++) {
            arrays[i] = selectIndexs.get(i);
        }
        return arrays;
    }

    public int getTextColor() {
        return textColor;
    }

    public StackLabel setTextColor(int textColor) {
        this.textColor = textColor;
        setLabels(labels);
        return this;
    }

    public int getTextSize() {
        return textSize;
    }

    public StackLabel setTextSize(int textSize) {
        this.textSize = textSize;
        setLabels(labels);
        return this;
    }

    public int getPaddingVertical() {
        return paddingVertical;
    }

    public StackLabel setPaddingVertical(int paddingVertical) {
        this.paddingVertical = paddingVertical;
        setLabels(labels);
        return this;
    }

    public int getPaddingHorizontal() {
        return paddingHorizontal;
    }

    public StackLabel setPaddingHorizontal(int paddingHorizontal) {
        this.paddingHorizontal = paddingHorizontal;
        setLabels(labels);
        return this;
    }

    public int getItemMargin() {
        return itemMargin;
    }

    public StackLabel setItemMargin(int itemMargin) {
        this.itemMargin = itemMargin;
        setLabels(labels);
        return this;
    }

    public int getItemMarginVertical() {
        return itemMarginVertical;
    }

    public StackLabel setItemMarginVertical(int itemMarginVertical) {
        this.itemMarginVertical = itemMarginVertical;
        setLabels(labels);
        return this;
    }

    public int getItemMarginHorizontal() {
        return itemMarginHorizontal;
    }

    public StackLabel setItemMarginHorizontal(int itemMarginHorizontal) {
        this.itemMarginHorizontal = itemMarginHorizontal;
        setLabels(labels);
        return this;
    }

    public int getMaxLines() {
        return maxLines;
    }

    public StackLabel setMaxLines(int maxLines) {
        this.maxLines = maxLines;
        return this;
    }

    private void log(Object s) {
        HiLog.info(hiLogLabel, ">>>", s.toString());
    }
}
